﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using System.Collections.ObjectModel;

namespace CodeAngel.Domain.Framework
{
    #region IProperty

    /// <summary>
    /// Interface for a property of an entity.
    /// </summary>
    public interface IProperty
    {
        /// <summary>
        /// Identifies the name of this property.
        /// </summary>
        string Name { get; }

        /// <summary>
        /// Identifies the name of this property that is appropriate to display to the user.
        /// </summary>
        string FriendlyName { get; }

        /// <summary>
        /// Identifies the parent entity that this property belongs to.
        /// </summary>
        Entity ParentEntity { get; }

        /// <summary>
        /// Determines if this property is in a valid state.
        /// </summary>
        bool IsValid();

        /// <summary>
        /// Gets a collection of rules that are currently invalid, if any.
        /// </summary>
        RuleCollection GetInvalidRules();
    }

    #endregion

    #region PropertyCollection

    /// <summary>
    /// Represents a collection of IProperty objects.
    /// </summary>
    public class PropertyCollection : List<IProperty>
    {
        #region Add
        
        /// <summary>
        /// Adds a property to this collection.
        /// </summary>
        public new void Add(IProperty property)
        {
            if (property != null) base.Add(property);
        }

        #endregion

        #region IsValid

        /// <summary>
        /// Determines if all properties in this collection are in a valid state.
        /// </summary>
        public bool IsValid()
        {
            foreach (var ThisProperty in this)
                if (!ThisProperty.IsValid()) return false;
            return true;
        }

        #endregion
    }

    #endregion

    #region UninitializedPropertyException

    /// <summary>
    /// Identifies that a property of an entity was accessed but was never initialized.
    /// </summary>
    public class UninitializedPropertyException : Exception
    {

        internal UninitializedPropertyException(string propertyName, Aggregate aggregate)
            : base("Cannot access property variable. Property variable has not been initialized: " + propertyName + " - Aggregate: " + aggregate.GetType().Name)
        {
            this.PropertyName = propertyName;
            this.Aggregate = aggregate;
        }

        public string PropertyName { get; private set; }
        public Aggregate Aggregate { get; private set; }
    }

    #endregion

    #region PropertyIsNullException

    /// <summary>
    /// Identifies that the value of a strong-typed property was accessed but could not be resolved 
    /// because that property is currently null.
    /// </summary>
    public class PropertyIsNullException : Exception
    {

        internal PropertyIsNullException(IProperty thisProperty)
            : base("Cannot access property. Property is null: " + thisProperty.Name)
        {
            this.Property = thisProperty;
        }

        public IProperty Property { get; private set; }

    }

    #endregion
}
